﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using UnityEditor;
using UnityEngine;
using UnityEditor.SceneManagement;
using UnityEngine.Networking;
using WorldMapNew;
using WorldMapTools;

// 道路编辑器文档：https://youzu.feishu.cn/docs/doccnOdFRDoET5y59HLhXdt2xic#AxhB4z

namespace Tools.Maptools.Editor
{
    public class SandBoxRoadGroup {
        string savePath = "Assets/ResourcesAssets/Config/road/";
        public List<SandBoxRoadInfo> roads = new List<SandBoxRoadInfo>();
        Vector3 v3_max;
        Vector3 v3_min;
        bool b_init_pos = false;
        public GameObject plane;
        public GameObject center;
        public float f_last_angle = 0;
        public Vector3 v3_last_pos = Vector3.zero;
        
        public void InitGroup(List<SandBoxRoadInfo> _roads)
        {
            for (int i = 0;i < roads.Count; i++)
            {
                if (!_roads.Contains(roads[i]))
                {
                    GameObject.DestroyImmediate(roads[i].gameObject);
                }
            }
            roads = _roads;
            ResetGroup();
        }

        // 重置道路组合 计算plane(最大最小点) 中心点 重置旋转 
        void ResetGroup()
        {
            // 从新计算plane center
            if (center == null)
            {
                center = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            }
            if (plane == null)
            {
                plane = GameObject.CreatePrimitive(PrimitiveType.Plane);
            }

            for (int i = 0; i < roads.Count; i++)
            {
                SandBoxRoadInfo road = roads[i];
    
                //road.gameObject.transform.parent = center.transform;
                //road.UpdateRoadMesh();
                Vector3 min = road.GetMinPos();
                if (!b_init_pos)
                {
                    v3_min = min;
                }
                else
                {
                    if (min.x < v3_min.x)
                    {
                        v3_min.x = min.x;
                    }
                    if (min.z < v3_min.z)
                    {
                        v3_min.z = min.z;
                    }
                }
                Vector3 max = road.GetMaxPos();
                if (!b_init_pos)
                {
                    v3_max = max;
                }
                else
                {
                    if (max.x > v3_max.x)
                    {
                        v3_max.x = max.x;
                    }
                    if (max.z > v3_max.z)
                    {
                        v3_max.z = max.z;
                    }
                }
                b_init_pos = true;
            }
          
            v3_last_pos = (v3_max + v3_min) * 0.5f;
            center.transform.position = v3_last_pos;
            plane.transform.position = v3_last_pos;
            plane.transform.localScale = new Vector3((v3_max.x - v3_min.x) * 0.1f, 1, (v3_max.z - v3_min.z) * 0.1f);
            for (int i = 0; i < roads.Count; i++)
            {
                SandBoxRoadInfo road = roads[i];
                road.SetOrigin(v3_last_pos);
            }
        }

        // 旋转组合
        public void RoateGroup(float angle)
        {
            f_last_angle = angle;
            for (int i = 0; i < roads.Count; i++)
            {
                SandBoxRoadInfo road = roads[i];

                Vector3 e = road.obj_center.transform.eulerAngles;
                e.y = angle;
                road.obj_center.transform.eulerAngles = e;
                road.RoadRotate(-angle,center.transform.position);
            }
            if (plane)
            {
                plane.transform.eulerAngles = center.transform.eulerAngles;
            }
        }

        public void MoveGroup(Vector3 dis)
        {
            for (int i = 0; i < roads.Count; i++)
            {
                SandBoxRoadInfo road = roads[i];
                road.RoadMove(dis);
            }
            if (plane)
            {
                plane.transform.position = center.transform.position;
            }
        }

        // 保存组合
        public void SaveGroup(string name)
        {
         
            // 路点配置 记录全地图所有的路点
            string filepath = savePath + name + ".txt";

            if (!File.Exists(filepath))
            {
                File.Delete(filepath);
            }

            FileStream fs = new System.IO.FileStream(filepath, System.IO.FileMode.Create,
                    System.IO.FileAccess.Write);
            StreamWriter sw = new System.IO.StreamWriter(fs, System.Text.Encoding.Default);
            string content = "";
            content += "type,points,r,name\n";
            content += "string,string,float,string\n";

            // 写入道路信息
            foreach (SandBoxRoadInfo road in roads)
            {
                if (road && road.gameObject)
                {
                    content += string.Format("{0},{1},{2},{3}\n",
                        road.GetRoadType(),road.GetRoadPoints(), 0, road.name);
                }
            }

            if (string.IsNullOrEmpty(content) == false)
            {
                sw.Write(content);
            }

            sw.Close();
            fs.Close();
            AssetDatabase.Refresh();
        }

        public void Destroy()
        {
            for (int i = 0;i < roads.Count;i++)
            {
                var road = roads[i];
                GameObject.DestroyImmediate(road.gameObject);
            }
            if(plane)
            {
                GameObject.DestroyImmediate(plane);
            }
            if (center)
            {
                GameObject.DestroyImmediate(center);
            }
        }
    }

    public class SandBoxCrossCheckInfo {
        Vector3 _start;
        Vector3 _end;
        public int _roadId;
        public int _idx;
        public int _type; // 几车道
        public float crossX = -1;
        public float crossY = -1;
        public Vector3 center;
        public float w;
        public float h;
        public float _size; 
        public SandBoxCrossCheckInfo(Vector3 start,Vector3 end,int roadId,int type,float size,int idx)
        {
            _roadId = roadId;
            _idx = idx;
            _type = type;
            _size = size;
            // 以start和end距原点距离判断起点和终点
            float dis = Vector3.Distance(start, Vector3.zero);
            float dis1 = Vector3.Distance(end, Vector3.zero);
            if (dis > dis1)
            {
                _start = end;
                _end = start;
            }
            else
            {
                _start = start;
                _end = end;
            }
            if (Mathf.Abs(_start.x - _end.x) <= 0.001) 
            {
                w = size;
                h =Mathf.Abs(_end.z - _start.z);
                crossX = _start.x;
            }
            else if (Mathf.Abs(_start.z - _end.z) <= 0.001)
            {
                h = size;
                w =Mathf.Abs(_end.x - _start.x);
                crossY = _start.z;
            }
            else
            {
                Debug.LogError("检测的线段没有保持直线 roadId : " + roadId);
            }
            w = w * 0.5f;
            h = h * 0.5f;
            center = (_start + _end) * 0.5f;
        }

        bool CheckBox(Vector3 center0, float w0, float h0)
        {
          
            bool res = false;
            Vector3 dis = center - center0;
            res = Mathf.Abs(dis.x) < (w + w0) && Mathf.Abs(dis.z) < (h + h0);
            Debug.Log(string.Format("[自动铺设衔接点] 检测碰撞 center:{0} center0{1} disX{2} disY{3} w+w0{4} h+h0{5}",
                       center.ToString(), center0.ToString(), Mathf.Abs(dis.x), Mathf.Abs(dis.z), (w + w0), (h + h0)));
            return res;
        }
        bool CheckContains(Vector3 point)
        {
            bool res = false;
            Vector3 dis = center - point;
            res = Mathf.Abs(dis.x) < w && Mathf.Abs(dis.z) < h;
            return res;
        }
        public SandBoxCrossInfo CheckCross(SandBoxCrossCheckInfo other)
        {
            SandBoxCrossInfo res = new SandBoxCrossInfo();
            if (_roadId == 43 && other._roadId == 53)
            {
                int a = 0;
            }
            res.bCross = CheckBox(other.center,other.w,other.h);
            if (res.bCross)
            {
                Debug.Log(string.Format("[自动铺设衔接点] 2 碰撞 id:{0}idx{1}-idx{2} id0{3}idx0{4}-idx0{5}",
                               _roadId, _idx, _idx + 1, other._roadId, other._idx, other._idx + 1));
                Vector3 center1 = new Vector3(Mathf.Max(crossX, other.crossX),0,Mathf.Max(crossY, other.crossY));
                res.pos = new Vector3(center1.x,0, center1.z);
                // 判断道路接口数 拼接道路预制体名字 预制体命名规范
                res.name = "Cross";
                string type = "_" + _type;
                string type1 = "_" + other._type;
                int port = CheckPort(center1, other._size);
                int port1 = other.CheckPort(center1, _size);
                Debug.Log(string.Format("[自动铺设衔接点] 3 拼接衔接点 id:{0}(crossX{1}，crossY{2})port{3} id0:{4}(crossX{5}，crossY{6})port0{7}",
                            _roadId, crossX, crossY, port, other._roadId, other.crossX, other.crossY, port1));
                if (port == 0 && port1 == 0) // 4接口
                {
                    if (crossX > 0) // x轴对齐
                    {
                        if (_type < other._type)
                        {
                            res.name = res.name + type1 + type + "_4";
                            res.angle = 90;
                        }
                        else        
                        {
                            res.name = res.name + type + type1 + "_4";
                            res.angle = 0;
                        }
                    }
                    else
                    {
                        if (_type < other._type)
                        {
                            res.name = res.name + type1 + type + "_4";
                            res.angle = 90;
                        }
                        else
                        {
                            res.name = res.name + type + type1 + "_4";
                            res.angle = 0;
                        }
                    }
                }
                else if (port != 0 && port1 == 0) // 3接口
                {
                    res.name = res.name + type1 + type + "_3";
                    if (crossX > 0) // x轴对齐
                    {
                        if (port > 0)
                        {
                            res.angle = 90;
                        }
                        else
                        {
                            res.angle = 270;
                        }
                    }
                    else
                    {
                        if (port > 0)
                        {
                            res.angle = 180;
                        }
                        else
                        {
                            res.angle = 0;
                        }
                    }
                }
                else if (port1 != 0 && port == 0) // 3接口
                {
                    res.name = res.name + type + type1 + "_3";
                       if (other.crossX > 0) // x轴对齐
                    {
                        if (port1 > 0)
                        {
                            res.angle = 90;
                        }
                        else
                        {
                            res.angle = 270;
                        }
                    }
                    else
                    {
                        if (port1 > 0)
                        {
                            res.angle = 180;
                        }
                        else
                        {
                            res.angle = 0;
                        }
                    }
                }
                else
                {
                    Debug.LogError("[自动铺设衔接点] 衔接点接口数判断错误 roadId : " + _roadId);
                }
            }
            return res;
        }

        public int CheckPort(Vector3 center,float size)
        {
            int res = 0;// -1 左边/下面 没有接口  1 右边/上面 没有接口
            if (crossX > 0)
            {
                // 检测自己的z轴方向上接口数
                res = (CheckContains(center + new Vector3(0,0, size)) ? res : 1);
                res = (CheckContains(center + new Vector3(0,0, -size)) ? res : -1);
            }
            else
            {
                // 检测自己的x轴方向上接口数
                res = (CheckContains(center + new Vector3(size, 0,0)) ? res : 1);
                res = (CheckContains(center + new Vector3(-size, 0,0)) ? res : -1);
            }
            return res;
        }
    }

    public struct SandBoxCrossInfo {
        public bool bCross;
        public Vector3 pos;
        public string name;
        public float angle;
    }

    public class SandBoxRoadEditor : EditorWindow
    {
        // =========================== 配置 ===========================

        struct RoadCfg
        {
            public string matName;
            public float width;
            public string light_prefab;
            public float light_space;
            public int road_width;
        }

        Dictionary<string, RoadCfg> map_road_cfg = new Dictionary<string, RoadCfg>();
        Dictionary<string, Material> map_road_mat = new Dictionary<string, Material>();

        // =========================== 变量 ===========================

        // 线框图
        private string road_texture_path = "Assets/Arts/Scene/Warpath_Road/Procedural_Road/Dynamic_Width/Textures/MapRoad/";
        Texture road_texture;
        Color[] road_texture_datas;
        int road_texture_width = 1200;
        int road_texture_height = 1200;

        // 道路映射配置 
        private string road_cfg_path = "Assets/ResourcesAssets/Config/road/";
        string road_cfg = "";

        // 道路
        int road_id_sum = 0;// 道路ID
        Dictionary<int, SandBoxRoadInfo> map_road_infos = new Dictionary<int, SandBoxRoadInfo>();
        Dictionary<int, int> map_road_added = new Dictionary<int, int>();
        string str_add_type = "";// 添加道路类型
        List<string> str_road_types = new List<string>();
        // 编辑器
        int editor_step = 0; // 当前编辑器操作步骤 位运算
        enum RoadEditorStep
        {
            E_INPORT_CFG = 1,   //  导入道路映射配置
            E_INPORT_OSM = 2,   //  导入道路OSM
            E_GENERATE_ROAD = 3,//  生成道路
            E_EXPORT_ROAD = 4,  //  导出道路
            E_GENERATE_ROAD2 = 5,//  用编辑器数据 生成道路 
        }
        string[] step_err_tips = {
            "未导入道路映射配置！亲 请导入道路映射配置",
            "未导入道路OSM！亲 请导入OSM",
            "未生成道路！亲 生成道路",
            "未导出道路！亲 导出道路",
            "未生成道路！亲 生成道路",
        };

        // OSM
        bool DevelopmentToolsCFoldOut = false;
        bool IsAllWayImport = true;
        private string road_osm_path = "Assets/ResourcesAssets/Config/Osm/";
        private XmlDocument doc = new XmlDocument();

        bool bload_osm_node = false;
        XmlNodeList elemList;
        int load_element_num = 0;
        int load_element_num_once = 10;
        private List<Node> nodes = new List<Node>();

        bool bload_osm_way = false;
        XmlNodeList wayList;
        int load_way_num = 0;
        int load_way_num_once = 10;
        private List<Way> ways = new List<Way>();

        bool bload_osm_road = false;
        int load_road_num = 0;
        int load_road_num_once = 100;

        string s_osm_x_0 = "33.3204000";
        string s_osm_y_0 = "-111.8703000";
        string s_osm_x_1 = "33.3389000";
        string s_osm_y_1 = "-111.8299000";
        string s_start_osm_x = "210";
        string s_start_osm_y = "0";
        string s_end_osm_x = "880";
        string s_end_osm_y = "340";
        private double osm_y_0 = 33.3204000;
        private double osm_x_0 = -111.8703000;
        private double osm_y_1 = 33.3389000;
        private double osm_x_1 = -111.8299000;
        double start_osm_x = 210;
        double start_osm_y = 0;
        double end_osm_x = 880;
        double end_osm_y = 340;
        private List<Transform> wayObjects = new List<Transform>();
        Dictionary<string, GameObject> roadTypeRoots = new Dictionary<string, GameObject>();

        GameObject model_road;
        float checkProgress = 0;
        // 选中
        SandBoxRoadInfo script_select_road;
        Vector3 v3_select_last_pos = Vector3.zero;
        GameObject obj_select_last;
        // 衔接点
        GameObject obj_cross;
        Dictionary<int, GameObject> map_obj_cross = new Dictionary<int, GameObject>();
        Dictionary<string, GameObject> crossTypeRoots = new Dictionary<string, GameObject>();
        // 导入导出配置
        string str_cfg_path = "Assets/ResourcesAssets/Config/road/";
        string str_cfg_prefab_path = "Assets/ResourcesAssets/World/prefabs/sandtable/road/";
        bool bload_cfg_road = false;
        string[] road_info_lines;
        int load_road_cfg = 2;
        int load_road_cfg_once = 10;

        bool b_import_all = false;
        bool b_editor_roadgroup = false;
        TextAsset obj_roadgroup_cfg;
        string s_roadgroup_cfg;
        // 地图数据
        GameObject map_root;
        int map_size = 1200;
        int map_cell_size = 40;
        GameObject ray_cube;
        Collider col_cube;
        // 道路组合
        SandBoxRoadGroup roadgroup;
        float f_delay_time = 0;
        // =========================== GUI ===========================

        private void OnGUI()
        {
            //
            GUILayout.BeginVertical();
            if (GUILayout.Button("1、导入道路映射配置"))
            {
                EditorCoroutines.StartCoroutine(InportRoadCfg(), this);
            }
            b_import_all = EditorGUILayout.Toggle("导入OSM全部种类的道路", b_import_all, GUILayout.Width(200));
            GUILayout.EndVertical();
            //
            GUILayout.BeginVertical();
            GUILayout.BeginHorizontal();
            GUILayout.Label("osm最小x:", GUILayout.Width(85));
            s_osm_x_0 = EditorGUILayout.TextField(s_osm_x_0, GUILayout.Width(60));
            Double.TryParse(s_osm_x_0, out osm_x_0);
            GUILayout.Label("osm最小y:", GUILayout.Width(85));
            s_osm_y_0 = EditorGUILayout.TextField(s_osm_y_0, GUILayout.Width(60));
            Double.TryParse(s_osm_y_0, out osm_y_0);
            GUILayout.Label("osm最大x:", GUILayout.Width(85));
            s_osm_x_1 = EditorGUILayout.TextField(s_osm_x_1, GUILayout.Width(60));
            Double.TryParse(s_osm_x_1, out osm_x_1);
            GUILayout.Label("osm最大y:", GUILayout.Width(85));
            s_osm_y_1 = EditorGUILayout.TextField(s_osm_y_1, GUILayout.Width(60));
            Double.TryParse(s_osm_y_1, out osm_y_1);
            GUILayout.EndHorizontal();
            GUILayout.BeginHorizontal();
            GUILayout.Label("osm文件对应地图最小x:", GUILayout.Width(140));
            s_start_osm_x = EditorGUILayout.TextField(s_start_osm_x, GUILayout.Width(60));
            Double.TryParse(s_start_osm_x, out start_osm_x);
            GUILayout.Label("osm文件对应地图最小x:", GUILayout.Width(140));
            s_start_osm_y = EditorGUILayout.TextField(s_start_osm_y, GUILayout.Width(60));
            Double.TryParse(s_start_osm_y, out start_osm_y);
            GUILayout.Label("osm文件对应地图最大x:", GUILayout.Width(140));
            s_end_osm_x = EditorGUILayout.TextField(s_end_osm_x, GUILayout.Width(60));
            Double.TryParse(s_end_osm_x, out end_osm_x);
            GUILayout.Label("osm文件对应地图最大x:", GUILayout.Width(140));
            s_end_osm_y = EditorGUILayout.TextField(s_end_osm_y, GUILayout.Width(60));
            Double.TryParse(s_end_osm_y, out end_osm_y);
            GUILayout.EndHorizontal();
            if (GUILayout.Button("2、导入OSM道路数据"))
            {
                EditorCoroutines.StartCoroutine(ImportRoadOSM(), this);
            }
            GUILayout.EndVertical();
            //
            GUILayout.BeginVertical();
            if (GUILayout.Button("3、生成OSM道路"))
            {
                if (CheckEditorStep(RoadEditorStep.E_GENERATE_ROAD))
                {
                    bload_osm_road = true;
                    load_road_num = 0;
                    checkProgress = 0;
                }
            }
            GUILayout.EndVertical();
            //

            DevelopmentToolsCFoldOut = CreateMapEditorWindow.FoldoutReset(DevelopmentToolsCFoldOut, "4、编辑道路");
            if (DevelopmentToolsCFoldOut)
            {
                GUILayout.BeginVertical();
                // 添加道路对象
                {
                    GUILayout.BeginHorizontal();
                    if (str_road_types.Count <= 0)
                    {
                        str_road_types.Add("null");
                    }
                    int index = 0;
                    index = EditorGUILayout.Popup(index, str_road_types.ToArray(), GUILayout.Width(200));
                    str_add_type = str_road_types[index];
                    if (GUILayout.Button("添加道路", GUILayout.Width(200)))
                    {
                        List<Vector3> v3_pos = new List<Vector3>();
                        v3_pos.Add(Vector3.zero);
                        AddRoad(road_id_sum + 1, 1, str_add_type, null, v3_pos.ToArray());
                    }
                    GUILayout.EndHorizontal();
                }
                // 添加道路其他预置
                {
                    GUILayout.BeginHorizontal();
                    obj_cross = EditorGUILayout.ObjectField("预制体", obj_cross, typeof(GameObject), true, GUILayout.Width(300)) as GameObject;
                    if (GUILayout.Button("添加道路其他预置", GUILayout.Width(200)))
                    {
                        AddCross2();
                    }
                    GUILayout.EndHorizontal();
                }
                // 自动铺设衔接点
                {
                    GUILayout.BeginHorizontal();
                    if (GUILayout.Button("自动铺设衔接点", GUILayout.Width(200)))
                    {
                        AddCrossAuto();
                    }
                    GUILayout.EndHorizontal();
                }
                // 组合道路编辑
                {
                    GUILayout.BeginHorizontal();
                    EditorGUI.BeginChangeCheck();
                    b_editor_roadgroup = EditorGUILayout.Toggle("开启道路组合编辑", b_editor_roadgroup, GUILayout.Width(200));
                    if (EditorGUI.EndChangeCheck())
                    {
                        f_delay_time = 0;
                        if (b_editor_roadgroup && roadgroup == null) // 勾选需要创建一个空的道路组合
                        {
                            roadgroup = new SandBoxRoadGroup();
                            //Tools.lockedLayers |= 1 << 20;
                        }
                        if (!b_editor_roadgroup && roadgroup != null) // 取消勾选需要删除当前道路组合
                        {
                            roadgroup.Destroy();
                            roadgroup = null;
                        }
                    }
                    if (roadgroup != null)
                    {
                        roadgroup.center = EditorGUILayout.ObjectField("当前道路组合", roadgroup.center, typeof(GameObject), false, GUILayout.Width(300)) as GameObject;
                    }
                    GUILayout.EndHorizontal();
                    GUILayout.BeginHorizontal();
                    obj_roadgroup_cfg = EditorGUILayout.ObjectField("道路组合配置", obj_roadgroup_cfg, typeof(TextAsset), false, GUILayout.Width(300)) as TextAsset;
                    if (GUILayout.Button("添加道路组合", GUILayout.Width(200)))
                    {
                        ImportRoadGroup();
                    }
                    GUILayout.EndHorizontal();
                    s_roadgroup_cfg = EditorGUILayout.TextField("道路组合命名", s_roadgroup_cfg, GUILayout.Width(300));
                }
                // 铺设路灯
                {
                    if (GUILayout.Button("铺设路灯", GUILayout.Width(200)))
                    {
                        AddRoadLight();
                    }
                }
                GUILayout.EndVertical();
            }

            if (GUILayout.Button("5、导出道路数据"))
            {
                if (CheckEditorOneStep(RoadEditorStep.E_GENERATE_ROAD) || CheckEditorOneStep(RoadEditorStep.E_GENERATE_ROAD2))
                {

                }
                ExportRoad();
                ExportRoad2();
                ShowNotification(new GUIContent("导出道路结束"));
            }
            if (GUILayout.Button("6、导入道路数据"))
            {
                ClearObjs();
                EditorCoroutines.StartCoroutine(ImportRoadCfg(), this);
            }
            map_root = EditorGUILayout.ObjectField("地图根节点", map_root, typeof(GameObject), true) as GameObject;
            if (GUILayout.Button("7、合并道路数据到地图数据中"))
            {
                if (map_root != null)
                {
                    // 添加道路
                    ExportRoadToMap();
                    // 添加衔接点
                    ExportRoadCrossToMap();
                    ShowNotification(new GUIContent("合并道路数据到地图数据结束"));
                }
            }

            // 
            if (bload_osm_node)
            {
                // 绘制进度条
                if (checkProgress < 1)
                {
                    string strTip = "当前解析OSM路点信息 ===== " + checkProgress * 100 + "% =====";
                    EditorUtility.DisplayProgressBar("OSM数据解析", strTip, checkProgress);
                }
                else
                {
                    CheckEnd("解析OSM路点信息结束");
                    checkProgress = 0.0f;
                    bload_osm_way = true;
                    bload_osm_node = false;
                }
            }
            if (bload_osm_way)
            {
                // 绘制进度条
                if (checkProgress < 1)
                {
                    string strTip = "当前解析OSM道路信息 ===== " + checkProgress * 100 + "% =====";
                    EditorUtility.DisplayProgressBar("OSM数据解析", strTip, checkProgress);
                }
                else
                {
                    CheckEnd("解析OSM道路信息结束");
                    checkProgress = 0.0f;
                    bload_osm_way = false;
                    editor_step = editor_step | (int)RoadEditorStep.E_INPORT_OSM;
                }
            }
            if (bload_osm_road)
            {
                // 绘制进度条
                if (checkProgress < 1)
                {
                    string strTip = "当前生成道路 ===== " + load_road_num + " =====";
                    EditorUtility.DisplayProgressBar("生成道路", strTip, checkProgress);
                }
                else
                {
                    CheckEnd("生成道路结束");
                    checkProgress = 0.0f;
                    bload_osm_road = false;
                }
            }
            if (bload_cfg_road)
            {
                // 绘制进度条
                if (checkProgress < 1)
                {
                    string strTip = "当前生成道路+衔接 ===== " + load_road_cfg + " =====";
                    EditorUtility.DisplayProgressBar("生成道路编辑数据", strTip, checkProgress);
                }
                else
                {
                    CheckEnd("生成道路编辑数据");
                    checkProgress = 0.0f;
                    bload_cfg_road = false;
                }
            }
            //
            Event e = Event.current;
            if (b_editor_roadgroup)
            {
                switch (e.keyCode)
                {
                    case KeyCode.S:
                        if (Event.current.control && f_delay_time <= 0)
                        {
                            f_delay_time = 2.0f;
                            CheckGroupExport();
                        }
                        break;
                    case KeyCode.C:
                        if (Event.current.control && f_delay_time <= 0)
                        {
                            f_delay_time = 2.0f;
                            CheckGroupChange();
                        }
                        break;
                    case KeyCode.V:
                        if (Event.current.control && f_delay_time <= 0)
                        {
                            f_delay_time = 2.0f;
                            CheckGroupCopy();
                        }
                        break;
                }
            }
        }

        // =========================== 逻辑函数 ===========================

        #region 道路线框图(暂时不用)

        // 导入道路线框图
        IEnumerator ImportRoadTexture()
        {
            // 选择默认路径 打开
            string path = EditorUtility.OpenFilePanel("道路线框图导入", road_texture_path, "png");
            if (!string.IsNullOrEmpty(path))
            {
                UnityWebRequest request = UnityWebRequest.Get(@"file://" + path);
                DownloadHandlerTexture texture = new DownloadHandlerTexture(true);
                request.downloadHandler = texture;
                yield return request.SendWebRequest();
                if (!request.isNetworkError)
                {
                    road_texture = texture.texture;
                    //if (road_texture != null)
                    //{
                    //    road_texture.wrapMode = TextureWrapMode.Clamp;
                    //}
                }
                if (UpdateRoadTexture())
                {
                    ShowNotification(new GUIContent("道路线框图导入成功!"));
                    //editor_step = editor_step | (int)RoadEditorStep.E_INPORT_PNG;
                    //editor_step = editor_step | (int)RoadEditorStep.E_INPORT_CFG; // 暂时不导入配置
                }
            }
            else
            {
                ShowNotification(new GUIContent("道路线框图错误!请检查线框图路径正确"));
                Debug.LogError("道路线框图错误! " + path);
            }
        }

        // 更新道路线框图 -根据当前数据
        bool UpdateRoadTexture()
        {
            bool bUpdateSuccess = true;

            return bUpdateSuccess;
        }

        #endregion

        #region 道路OSM数据
        IEnumerator ImportRoadOSM()
        {
            // 选择默认路径 打开
            string path = EditorUtility.OpenFilePanel("道路OSM导入", road_osm_path, "osm");
            if (!string.IsNullOrEmpty(path))
            {
                doc.Load(new XmlTextReader(path));
                yield return null;
                // 清空osm数据
                elemList = null;
                nodes.Clear();
                load_element_num = 0;

                bload_osm_node = true;
            }
            else
            {
                ShowNotification(new GUIContent("道路线框图错误!请检查线OSM径正确"));
                Debug.LogError("道路线框图错误! " + path);
            }
        }

        // 解析OSM数据
        void GetOsmNodeData()
        {
            if (elemList == null)
            {
                elemList = doc.GetElementsByTagName("node");
            }
            for (int i = load_element_num; i < elemList.Count && i < (load_element_num + load_element_num_once); i++)
            {
                nodes.Add(new Node(double.Parse(elemList[i].Attributes["id"].InnerText),
                    float.Parse(elemList[i].Attributes["lat"].InnerText),
                    float.Parse(elemList[i].Attributes["lon"].InnerText)
                ));
            }
            load_element_num += load_element_num_once;
            load_element_num = Mathf.Min(load_element_num, elemList.Count);
            UpdateCheckProgress(load_element_num, elemList.Count);

        }

        void GetOsmWaysData()
        {
            if (wayList == null)
            {
                wayList = doc.GetElementsByTagName("way");
            }
            for (int i = load_way_num; i < wayList.Count && i < (load_way_num + load_way_num_once); i++)
            {
                XmlNode node = wayList.Item(i);
                XmlNodeList wayNodes = node.ChildNodes;
                Way w = new Way(int.Parse(node.Attributes["id"].InnerText));
                ways.Add(w);
                foreach (XmlNode nd in wayNodes)
                {
                    if (nd.Attributes[0].Name == "ref")
                    {
                        ways[i].wnodes.Add(double.Parse(nd.Attributes["ref"].InnerText));
                    }
                }

                XmlNodeList tags = node.SelectNodes("tag");
                foreach (XmlNode t in tags)
                {
                    string key = GetAttribute<string>("k", t.Attributes);
                    if (key == "highway")//是路
                    {
                        w.type = GetAttribute<string>("v", t.Attributes);
                    }
                }
            }
            load_way_num += load_way_num_once;
            load_way_num = Mathf.Min(load_way_num, wayList.Count);
            if (load_way_num >= wayList.Count - 1)
            {
                checkProgress = 1.0f;
                Repaint();
            }
            else
            {
                checkProgress = load_way_num * 1.0f / wayList.Count;
            }
        }

        T GetAttribute<T>(string attrName, XmlAttributeCollection attributes)
        {
            string strValue = attributes[attrName].Value;
            return (T)Convert.ChangeType(strValue, typeof(T));
        }
        void CheckEnd(string tip)
        {
            EditorUtility.ClearProgressBar();
            ShowNotification(new GUIContent(tip));
        }

        #endregion

        #region 道路类型映射文件

        // 导入道路配置 线框图线段对应的道路配置
        IEnumerator InportRoadCfg()
        {
            // 选择默认路径 打开
            string path = EditorUtility.OpenFilePanel("道路映射配置导入", road_cfg_path, "txt");
            path = GetPath(path);

            if (!string.IsNullOrEmpty(path))
            {
                TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                if (content != null && content.text != null && content.text.Length > 0)
                {
                    var csvText = content.text.Trim();
                    var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

                    for (int i = 3; i < lines.Length; i++)
                    {
                        var l = lines[i];
                        var data = l.Split(',');

                        if (data.Length == 6)
                        {
                            string type = data[0];
                            string matName = data[1];
                            float.TryParse(data[2], out float width);
                            string light_prefab = data[3];
                            float.TryParse(data[4], out float light_space);
                            int.TryParse(data[5], out int road_width);
                            RoadCfg cfg = new RoadCfg();
                            cfg.matName = matName;
                            cfg.width = width;
                            cfg.light_prefab = light_prefab;
                            cfg.light_space = light_space;
                            cfg.road_width = road_width;
                            map_road_cfg[type] = cfg;
                            str_road_types.Add(type);
                        }
                    }
                    editor_step = editor_step | (int)RoadEditorStep.E_INPORT_CFG;
                    ShowNotification(new GUIContent("道路映射配置导入成功!"));
                }
                yield return null;
            }
            else
            {
                ShowNotification(new GUIContent("道路映射配置错误!请检查道路映射配置路径正确"));
                Debug.LogError("道路映射配置错误! " + path);
            }
        }

        #endregion

        #region 道路的生成 和 导出

        void GetRoads()
        {
            for (int i = load_road_num; i < ways.Count && i < (load_road_num + load_road_num_once); i++)
            {
                //if(ways[i].type == "secondary" || == "tertiary" || ways[i].type == "primary")
                if (map_road_cfg.ContainsKey(ways[i].type) || b_import_all)
                {
                    AddRoad(i, ways[i].wnodes.Count, ways[i].type, ways[i]);
                }
            }
            load_road_num += load_road_num_once;
            load_road_num = Mathf.Min(load_road_num, ways.Count);
            if (load_road_num >= ways.Count - 1)
            {
                checkProgress = 1.0f;
            }
            else
            {
                checkProgress = load_road_num * 1.0f / ways.Count;
            }
        }

        Material GetRoadMat(string name)
        {
            Material res = null;
            if (map_road_mat.ContainsKey(name))
            {
                res = map_road_mat[name];
            }
            else
            {
                res = AssetDatabase.LoadAssetAtPath<Material>("Assets/ResourcesAssets/Materials/Road/" + name + ".mat");
                map_road_mat[name] = res;
            }
            return res;
        }

        SandBoxRoadInfo AddRoad(int road_id, int point_count, string road_type, Way way, Vector3[] points = null,string checkIdx = "")
        {
            // road_id == 0 表示添加的道路是一组临时道路
            if (road_id != 0)
            {
                road_id_sum = Mathf.Max(road_id_sum, road_id);
                road_id_sum++;
            }

            if (model_road == null)
            {
                model_road = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/ResourcesAssets/World/prefabs/sandtable/road/Road.prefab");
            }

            GameObject obj = GameObject.Instantiate(model_road);
            SandBoxRoadInfo info = obj.GetComponent<SandBoxRoadInfo>();
            RoadCfg cfg = map_road_cfg[road_type];
            GameObject obj_light = null;
            if (cfg.light_prefab.Length > 0)
            {
                obj_light = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/ResourcesAssets/World/prefabs/sandtable/road/" + cfg.light_prefab + ".prefab");
            }

            info.InitRoad(road_id, point_count, road_type, obj_light,cfg.light_space);
            info.UpdateRoad(GetRoadMat(cfg.matName), cfg.width);
            if (checkIdx.Length > 0)
            {
                info.SetCheckCrossPoints(checkIdx);
            }
            if (way != null)
            {
                for (int j = 0; j < point_count; j++)
                {
                    double x = 0;
                    double y = 0;
                    foreach (Node nod in nodes)
                    {
                        if (nod.id == way.wnodes[j])
                        {
                            x = (nod.lat - osm_x_0) * (end_osm_x - start_osm_x) / (osm_x_1 - osm_x_0) + start_osm_x;
                            y = (nod.lon - osm_y_0) * (end_osm_y - start_osm_y) / (osm_y_1 - osm_y_0) + start_osm_y;
                            break;
                        }
                    }
                    Vector3 point_pos = new Vector3((float)x, 0, (float)y);
                    //PointRotate(start_pos,ref point_pos, -45);
                    info.SetRoadPoint(j, point_pos);
                    //Debug.Log(string.Format("添加路点 roadid:{0} idx:{1} pos({2},{3})", i, j, x, y));
                }
            }
            else
            {
                //
                for (int j = 0; j < point_count; j++)
                {
                    //PointRotate(start_pos, ref points[j], 0);
                    info.SetRoadPoint(j, points[j]);
                }
                info.UpdateRoadMesh();
            }
            info.SetOrigin(info.obj_center.transform.position);
            if (road_id == 0)
            {
                return info;
            }

            obj.name = "wayObject_" + road_id;
            wayObjects.Add(obj.transform);
            map_road_infos[road_id] = info;

            GameObject objRoot = null;
            if (roadTypeRoots.ContainsKey(road_type))
            {
                objRoot = roadTypeRoots[road_type];
            }
            else
            {
                objRoot = new GameObject();
                roadTypeRoots[road_type] = objRoot;
                objRoot.name = road_type;
            }
            obj.transform.parent = objRoot.transform;
            return info;
        }

        SandBoxRoadInfo AddCross(string roadtype, int id, Vector3 point, float r)
        {
            GameObject cross_model = AssetDatabase.LoadAssetAtPath<GameObject>(str_cfg_prefab_path + roadtype + ".prefab");
            GameObject cross = GameObject.Instantiate<GameObject>(cross_model);

            cross.transform.position = point;
            cross.transform.eulerAngles = new Vector3(0, r, 0);
            SandBoxRoadInfo info = cross.AddComponent<SandBoxRoadInfo>();
            info.InitRoad(id, 0, roadtype);
            //
            MeshCollider mesh_c = cross.AddComponent<MeshCollider>();
            MeshFilter mesh_f = cross.GetComponent<MeshFilter>();
            if (mesh_f == null)
            {
                mesh_f = cross.GetComponentInChildren<MeshFilter>();
            }
            mesh_c.sharedMesh = mesh_f.sharedMesh;

            if (id == 0)
            {
                return info;
            }

            // 设置name 添加到数据中
            cross.name = roadtype + "_" + id;
            map_obj_cross[id] = cross;
            road_id_sum = id + 1;
            // 设置父节点
            GameObject objRoot = null;
            if (crossTypeRoots.ContainsKey(roadtype))
            {
                objRoot = crossTypeRoots[roadtype];
            }
            else
            {
                objRoot = new GameObject();
                crossTypeRoots[roadtype] = objRoot;
                objRoot.name = roadtype;
            }
            cross.transform.parent = objRoot.transform;

            return info;
        }

        // 导出当前道路
        void ExportRoad()
        {
            // 导出所有衔接点和道路信息到

            // 路点配置 记录全地图所有的路点
            string filepath = str_cfg_path + "road_cfg" + ".txt";

            if (!File.Exists(filepath))
            {
                File.Delete(filepath);
            }

            FileStream fs = new System.IO.FileStream(filepath, System.IO.FileMode.Create,
                    System.IO.FileAccess.Write);
            StreamWriter sw = new System.IO.StreamWriter(fs, System.Text.Encoding.Default);
            string content = "";
            content += "id,type,points,r,name,checkidxs\n";
            content += "int32t,string,string,float,string,string\n";

            // 写入道路信息
            foreach (SandBoxRoadInfo road in map_road_infos.Values)
            {
                if (road && road.gameObject)
                {
                    content += string.Format("{0},{1},{2},{3},{4},{5}\n",
                        road.road_id, road.gameObject.transform.parent.name,
                        road.GetRoadPoints(), 0, road.name, road.GetCheckCrossPoints());
                }
            }
            // 写入交叉点信息
            foreach (int cross_id in map_obj_cross.Keys)
            {
                GameObject cross = map_obj_cross[cross_id];
                if (cross)
                {
                    Vector3 v3 = cross.transform.position;
                    content += string.Format("{0},{1},{2},{3},{4}\n",
                        cross_id, cross.gameObject.transform.parent.name,
                            string.Format("{0}_{1}_{2}|", v3.x, v3.y, v3.z), cross.transform.eulerAngles.y, "");
                }
            }

            if (string.IsNullOrEmpty(content) == false)
            {
                sw.Write(content);
            }

            sw.Close();
            fs.Close();
            AssetDatabase.Refresh();

        }

        // 导出工程用配置
        void ExportRoad2()
        {
            WorldRoadData mapData = ScriptableObject.CreateInstance<WorldRoadData>();
            foreach (SandBoxRoadInfo road in map_road_infos.Values)
            {
                if (road && road.gameObject)
                {
                    RoadInfo info = new RoadInfo();
                    info.objType = RoadObjType.E_ROAD;
                    info.type = road.gameObject.transform.parent.name;
                    info.points = road.GetRoadPointList();
                    info.roadId = road.road_id;
                    mapData.roadInfos.Add(info);
                }
            }
            foreach (int cross_id in map_obj_cross.Keys)
            {
                GameObject cross = map_obj_cross[cross_id];
                if (cross)
                {
                    RoadInfo info = new RoadInfo();
                    info.type = cross.gameObject.transform.parent.name;
                    info.objType = RoadObjType.E_CROSS;

                    if (info.type.Contains("bridge"))
                    {
                        info.objType = RoadObjType.E_BRIDGE;
                    }

                    info.roadId = cross_id;
                    info.r = cross.gameObject.transform.eulerAngles.y;
                    List<Vector3> points = new List<Vector3>();
                    points.Add(cross.transform.position);
                    info.points = points.ToArray();
                    mapData.roadInfos.Add(info);
                }
            }
            foreach (string type in map_road_cfg.Keys)
            {
                RoadCfg cfg = map_road_cfg[type];
                RoadTypeInfo info = new RoadTypeInfo();
                info.matName = cfg.matName;
                info.width = cfg.width;
                info.type = type;
                mapData.roadTypes.Add(info);
            }
            //
            AssetDatabase.CreateAsset(mapData, str_cfg_path + "/" + "road_cfg" + "_mapdata.asset");
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        // 加载道路导出配置
        IEnumerator ImportRoadCfg()
        {
            // 选择默认路径 打开
            string path = EditorUtility.OpenFilePanel("道路编辑数据导入", str_cfg_path, "txt");
            path = GetPath(path);
            if (!string.IsNullOrEmpty(path))
            {
                TextAsset content = AssetDatabase.LoadAssetAtPath<TextAsset>(path);
                if (content != null && content.text != null && content.text.Length > 0)
                {
                    var csvText = content.text.Trim();
                    road_info_lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    bload_cfg_road = true;
                }
                yield return null;
            }
            else
            {
                ShowNotification(new GUIContent("道路编辑数据导入!请检查配置路径正确"));
                Debug.LogError("道路编辑数据导入! " + path);
            }
        }

        void GetRoadCfgData()
        {
            for (int i = load_road_cfg; i < road_info_lines.Length && i < load_road_cfg + load_road_cfg_once; i++)
            {
                var l = road_info_lines[i];
                var data = l.Split(',');

                int.TryParse(data[0], out int id);
                string roadtype = data[1];
                bool braod = !(roadtype.Contains("Cross") || roadtype.Contains("bridge"));// 名字没有cross就是路 之后修改
                Vector3[] points = GetRoadPointData(data[2]);
                float.TryParse(data[3], out float r);
                string name = data[4];
                string checkIdx = "";
                if (data.Length > 5)
                {
                    checkIdx = data[5]; 
                }
                // 创建对象
                if (braod)
                {
                    AddRoad(id, points.Length, roadtype, null, points, checkIdx);
                }
                else
                {
                    AddCross(roadtype, id, points[0], r);
                }
            }

            load_road_cfg += load_road_cfg_once;
            load_road_cfg = Mathf.Min(load_road_cfg, road_info_lines.Length);
            if (load_road_cfg >= road_info_lines.Length - 1)
            {
                checkProgress = 1.0f;
            }
            else
            {
                checkProgress = load_road_cfg * 1.0f / road_info_lines.Length;
            }
        }

        Vector3[] GetRoadPointData(string data)
        {
            List<Vector3> res = new List<Vector3>();
            var points = data.Split('|');
            for (int i = 0; i < points.Length; i++)
            {
                var pos = points[i].Split('_');

                if (pos.Length == 3)
                {
                    float.TryParse(pos[0], out float x);
                    float.TryParse(pos[1], out float y);
                    float.TryParse(pos[2], out float z);
                    res.Add(new Vector3(x, y, z));
                }
                if (pos.Length == 2)
                {
                    float.TryParse(pos[0], out float x);
                    float.TryParse(pos[1], out float y);
                    res.Add(new Vector3(x, 0, y));
                }
            }
            return res.ToArray();
        }

        #endregion

        #region 衔接点

        GameObject AddCross2()
        {
            GameObject cross = null;
            if (obj_cross != null)
            {
                // 
                cross = GameObject.Instantiate<GameObject>(obj_cross);
                SandBoxRoadInfo info = cross.AddComponent<SandBoxRoadInfo>();
                info.InitRoad(road_id_sum, 0, obj_cross.name);
                cross.name = obj_cross.name + "_" + road_id_sum;
                map_obj_cross[road_id_sum] = cross;
                road_id_sum++;

                GameObject objRoot = null;
                if (crossTypeRoots.ContainsKey(obj_cross.name))
                {
                    objRoot = crossTypeRoots[obj_cross.name];
                }
                else
                {
                    objRoot = new GameObject();
                    crossTypeRoots[obj_cross.name] = objRoot;
                    objRoot.name = obj_cross.name;
                }
                cross.transform.parent = objRoot.transform;
            }
            else
            {
                ShowNotification(new GUIContent("添加衔接点失败!请选择衔接点预制体"));
            }
            return cross;
        }

        // 自动添加衔接点
        void AddCrossAuto()
        {
            // 删除当前所有衔接点
            foreach (GameObject cross in crossTypeRoots.Values)
            {
                if (cross)
                {
                    GameObject.DestroyImmediate(cross);
                }
            }
            crossTypeRoots.Clear();
            map_obj_cross.Clear();
            Dictionary<int, List<SandBoxCrossCheckInfo>> checks = new Dictionary<int, List<SandBoxCrossCheckInfo>>();
            Dictionary<string, SandBoxCrossInfo> checkRes = new Dictionary<string, SandBoxCrossInfo>();
            // 添加所有包围盒
            foreach (int i in map_road_infos.Keys)
            {
                SandBoxRoadInfo info = map_road_infos[i];
                if (info != null)
                {
                    List<int> idxs = info.check_idxs;
                    foreach(int idx in idxs)
                    {
                        if (idx >= info.render.positionCount)
                        {
                            Debug.Log("导出下标存在错误 road_id : " + info.road_id);
                        }
                        Vector3 start = info.render.GetPosition(idx);
                        Vector3 end = info.render.GetPosition(idx + 1);
                        RoadCfg cfg = map_road_cfg[info.GetRoadType()];
                        SandBoxCrossCheckInfo check = new SandBoxCrossCheckInfo(start, end, info.road_id, cfg.road_width, cfg.width,idx);
                        if (checks.ContainsKey(info.road_id) == false)
                        {
                            List<SandBoxCrossCheckInfo> list = new List<SandBoxCrossCheckInfo>();
                            checks[info.road_id] = list;
                        }
                        checks[info.road_id].Add(check);
                    }
                }
            }
            // 计算所有包围盒 
            foreach (int id in checks.Keys)
            {
                List<SandBoxCrossCheckInfo> listCheck = checks[id];
                // 遍历listCheck
                foreach (SandBoxCrossCheckInfo check in listCheck)
                {
                    foreach (int id0 in checks.Keys)
                    {
                        if (id != id0)
                        {
                            List<SandBoxCrossCheckInfo> listCheck0 = checks[id0];
                            // 遍历listCheck0
                            foreach (SandBoxCrossCheckInfo check0 in listCheck0)
                            {
                                Debug.Log(string.Format("[自动铺设衔接点] 1 检测 id:{0}idx{1}-idx{2} id0{3}idx0{4}-idx0{5}",
                                    id,check._idx,check._idx+1,id0,check0._idx,check0._idx+1));
                                SandBoxCrossInfo res = check.CheckCross(check0);
                                int id1 = Mathf.Min(id, id0);
                                int id2 = Mathf.Max(id, id0);
                                int id3 = Mathf.Min(check._idx, check0._idx);
                                int id4 = Mathf.Max(check._idx, check0._idx);
                                string key = string.Format("{0}_{1}_{2}_{3}", id1, id2, id3, id4);
                                if (res.bCross && checkRes.ContainsKey(key) == false)
                                {
                                    checkRes[key] = res;
                                    Debug.Log(string.Format("[自动铺设衔接点] 4 添加衔接点 id:{0}idx{1}-idx{2} id0{3}idx0{4}-idx0{5} res:[name:{6} pos{7} angle{8}]",
                                 id, check._idx, check._idx + 1, id0, check0._idx, check0._idx + 1, res.name, res.pos.ToString(),res.angle));
                                }
                            }
                        }
                    }
                }
            }
            // 添加所有衔接点
            foreach (SandBoxCrossInfo crossInfo in checkRes.Values)
            {
                obj_cross = AssetDatabase.LoadAssetAtPath<GameObject>(str_cfg_prefab_path + crossInfo.name + ".prefab");
                GameObject cross = AddCross2();
                if (cross == null)
                {
                    Debug.LogError("[自动铺设衔接点] 添加失败 name ： " + crossInfo.name);
                }
                else
                {
                    cross.transform.position = crossInfo.pos;
                    cross.transform.eulerAngles = new Vector3(0, crossInfo.angle, 0);
                }
            }
        }

        #endregion

        #region 道路组合编辑功能
        void ImportRoadGroup()
        {
            if (b_editor_roadgroup && obj_roadgroup_cfg != null)
            {
                List<SandBoxRoadInfo> roads = new List<SandBoxRoadInfo>();
                var csvText = obj_roadgroup_cfg.text.Trim();
                var lines = csvText.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

                for (int i = 2; i < lines.Length; i++)
                {
                    var l = lines[i];
                    var data = l.Split(',');

                    if (data.Length == 4)
                    {
                        string type = data[0];
                        Vector3[] points = GetRoadPointData(data[1]);
                        float.TryParse(data[2], out float r);
                        string name = data[3];
                        bool broad = !(type.Contains("Cross") || type.Contains("bridge"));// 名字没有cross就是路 之后修改
                        SandBoxRoadInfo road = null;
                        if (broad)
                        {
                            road = AddRoad(0, points.Length, type, null, points);
                        }
                        else
                        {
                            road = AddCross(type, 0, points[0], r);
                        }
                        roads.Add(road);
                    }
                }
                if (roadgroup != null)
                {
                    roadgroup.Destroy();
                    roadgroup = null;
                }
                roadgroup = new SandBoxRoadGroup();
                roadgroup.InitGroup(roads);
            }
            else
            {
                ShowNotification(new GUIContent("请选择正确的道路组合配置！"));
            }
        }
        void CheckGroupChange()
        {
            if (Selection.gameObjects.Length != roadgroup.roads.Count)
            {
                List<SandBoxRoadInfo> select_roads = new List<SandBoxRoadInfo>();
                List<GameObject> select_objs = new List<GameObject>();
                for (int i = 0; i < Selection.gameObjects.Length; i++)
                {
                    GameObject obj = Selection.gameObjects[i];
                    SandBoxRoadInfo road = obj.GetComponent<SandBoxRoadInfo>();
                    if (road)
                    {
                        if (road.road_id > 0)
                        {
                            SandBoxRoadInfo _road = null;
                            if (road.broad)
                            {
                                Vector3[] points = road.GetRoadPointList();
                                _road = AddRoad(0, points.Length, road.GetRoadType(), null, points);
                            }
                            else
                            {
                                Vector3[] points = road.GetRoadPointList();
                                _road = AddCross(road.GetRoadType(), 0, points[0], road.transform.eulerAngles.y);
                            }
                            select_roads.Add(_road);
                            select_objs.Add(_road.gameObject);
                        }
                        else
                        {
                            select_roads.Add(road);
                            select_objs.Add(road.gameObject);
                        }
                    }
                }
                Selection.objects = select_objs.ToArray();
                if (select_roads.Count != roadgroup.roads.Count)
                {
                    roadgroup.InitGroup(select_roads);
                }
            }
        }
        void CheckGroupRotate()
        {
            if (roadgroup.center == null) return;
            if (roadgroup.center.transform.eulerAngles.y != roadgroup.f_last_angle)
            {
                roadgroup.RoateGroup(roadgroup.center.transform.eulerAngles.y);
            }
        }
        void CheckGroupMove()
        {
            if (roadgroup.center)
            {
                Vector3 v0 = roadgroup.v3_last_pos;
                Vector3 v1 = roadgroup.center.transform.position;

                if ((v1 - v0).magnitude > 0.1f)
                {
                    roadgroup.v3_last_pos = roadgroup.center.transform.position;
                    roadgroup.MoveGroup(v1 - v0);
                }
            }
        }
        void CheckGroupCopy()
        {
            if (roadgroup != null)
            {
                for (int i = 0;i < roadgroup.roads.Count; i++)
                {
                    SandBoxRoadInfo road = roadgroup.roads[i];
                    Vector3[] points = road.GetRoadPointList();
                    if (road.broad)
                    {
                        AddRoad(road_id_sum + 1, points.Length, road.GetRoadType(), null, points);
                    }
                    else
                    {
                        AddCross(road.GetRoadType(), road_id_sum + 1, points[0], road.transform.eulerAngles.y);
                    }
                }
            }
        }
        void CheckGroupExport()
        {
            if (roadgroup != null)
            {
                if (s_roadgroup_cfg.Length <= 0)
                {
                    ShowNotification(new GUIContent("请填写导出的道路组合名"));
                }
                else
                {
                    roadgroup.SaveGroup(s_roadgroup_cfg);
                }
            }
            else
            {
                ShowNotification(new GUIContent("当前不存在道路组合！无法导出"));
            }
        }
        #endregion

        #region 其他
        // 检查当前步骤
        bool CheckEditorStep(RoadEditorStep step)
        {
            bool res = true;
            Type step_enum_type = typeof(RoadEditorStep);
            int step_idx = 0;
            foreach (int _step in Enum.GetValues(step_enum_type))
            {
                if (((int)step > _step))
                {
                    res = (editor_step & (int)_step) == _step;
                    // 前置步骤缺失
                    if (!res)
                    {
                        ShowNotification(new GUIContent("操作失败! => " + step_err_tips[step_idx]));
                    }
                }
                else
                {
                    break;
                }
                step_idx++;
            }
            return res;
        }
        bool CheckEditorOneStep(RoadEditorStep step)
        {
            bool res = true;
            res = ((editor_step & (int)step)) == (int)step;
            return res;
        }
        // 清除所有生成的节点
        void ClearObjs()
        {
            foreach (GameObject road in roadTypeRoots.Values)
            {
                if (road)
                {
                    GameObject.DestroyImmediate(road);
                }
            }
            roadTypeRoots.Clear();
            foreach (GameObject cross in crossTypeRoots.Values)
            {
                if (cross)
                {
                    GameObject.DestroyImmediate(cross);
                }
            }
            crossTypeRoots.Clear();
            if (roadgroup != null)
            {
                roadgroup.Destroy();
                roadgroup = null;
            }
        }

        void PointRotate(Vector3 center, ref Vector3 p1, double angle)
        {
            double res_x = (p1.x - center.x) * Math.Cos(angle) + (p1.z - center.z) * Math.Sin(angle) + center.z;
            double res_z = -(p1.x - center.x) * Math.Sin(angle) + (p1.z - center.z) * Math.Cos(angle) + center.z;
            p1.x = (float)res_x;
            p1.z = (float)res_z;
        }

        void UpdateCheckProgress(int cur, int all)
        {
            if (cur >= all - 1)
            {
                checkProgress = 1.0f;
            }
            else
            {
                checkProgress = cur * 1.0f / all;
            }
        }

        string GetPath(string path)
        {
            string res = "";
            string[] paths = path.Split('/');
            int start_idx = 0;
            for (int i = 0; i < paths.Length; i++)
            {
                if (paths[i] == "Assets")
                {
                    start_idx = i;
                    res = "Assets/";
                }
                if (i > start_idx)
                {
                    if (i < paths.Length - 1)
                    {
                        res += (paths[i] + "/");
                    }
                    else
                    {
                        res += (paths[i]);
                    }
                }
            }
            return res;
        }

        // 铺设路灯 
        void AddRoadLight()
        {
            // 删除之前的所有路灯
            // 
            for (int i = 0;i < map_road_infos.Count; i++)
            {
                SandBoxRoadInfo road = map_road_infos[i];
                if (road.broad)
                {
                    road.RemoveLight();
                    road.AddLight();
                }
            }
        }

        #endregion

        #region 道路数据导入到地图

        void ExportRoadToMap()
        {
            if (ray_cube == null)
            {
                ray_cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
                ray_cube.transform.localScale = new Vector3(map_cell_size, map_cell_size, map_cell_size);
                ray_cube.transform.eulerAngles = new Vector3(90, 0, 0);
                col_cube = ray_cube.GetComponent<Collider>();
            }
            // 射线检测
            int line_num = map_size / map_cell_size;
            float half_cell_size = map_cell_size * 0.5f;
            for (int x = 0; x < line_num; x++)
            {
                for (int y = 0; y < line_num; y++)
                {
                    ray_cube.transform.position = new Vector3(x * map_cell_size + half_cell_size, 100, y * map_cell_size + half_cell_size);
                    RaycastHit[] ray_res = Physics.BoxCastAll(col_cube.bounds.center, ray_cube.transform.localScale * 0.5f, ray_cube.transform.forward, ray_cube.transform.rotation, 1000);
                    for (int i = 0; i < ray_res.Length; i++)
                    {
                        RaycastHit ray = ray_res[i];
                        Transform parent = ray.collider.gameObject.transform.parent;
                        if (parent == null)
                        {
                            continue;
                        }
                        SandBoxRoadInfo roadInfo = parent.gameObject.GetComponent<SandBoxRoadInfo>();
                        if (roadInfo == null || roadInfo.s_road_type.Contains("Cross"))
                        {
                            continue;
                        }

                        //string[] str = ray.collider.gameObject.name.Split('_');
                        //int.TryParse(str[str.Length - 1], out int id);
                        //Debug.Log("射线检测 ================> " + string.Format("pos({0},{1}) id:{2}", x, y, id));
                        //
                        int idx = x + line_num * y;
                        Transform tf_tile = map_root.transform.GetChild(idx); // 因为root子节点的地图块是按照一维坐标添加的
                        Transform layer = GetChildByName(tf_tile, "LayerRoad", true);
                        Transform lod = GetChildByName(layer, "LOD0", true);
                        // 添加节点
                        GameObject road = new GameObject();
                        road.name = string.Format("OBJ<Assets/ResourcesAssets/World/prefabs/sandtable/road/Road_{0}.prefab>", roadInfo.road_id);
                        // Debug.Log("name ： " + road.name,roadInfo.gameObject);
                        road.transform.parent = lod;
                        Vector3 pos0 = ray_cube.transform.position;
                        road.transform.position = new Vector3(pos0.x, 0, pos0.z);
                    }
                }
            }
        }

        Transform GetChildByName(Transform node, string name, bool bAdd = false)
        {
            Transform res = null;
            for (int i = 0; i < node.childCount; i++)
            {
                Transform t = node.GetChild(i);
                if (t.name == name)
                {
                    res = t;
                    break;
                }
            }
            if (res == null && bAdd)
            {
                GameObject root = new GameObject();
                res = root.transform;
                root.transform.parent = node;
                root.name = name;
            }
            return res;
        }
        void ExportRoadCrossToMap()
        {
            foreach (int key in map_obj_cross.Keys)
            {
                GameObject cross = map_obj_cross[key];

                // 计算该点坐标位于哪个地图块中
                int idx_x = (int)(cross.transform.position.x / map_cell_size);
                int idx_y = (int)(cross.transform.position.z / map_cell_size);
                int idx = idx_x + idx_y * (map_size / map_cell_size);

                // 向地图块中添加数据
                if (map_root != null && idx < map_root.transform.childCount)
                {
                    Transform tf_tile = map_root.transform.GetChild(idx); // 因为root子节点的地图块是按照一维坐标添加的
                    Transform layer = GetChildByName(tf_tile, "LayerRoad", true);
                    Transform lod = GetChildByName(layer, "LOD0", true);
                    // 添加节点
                    GameObject road = new GameObject();
                    road.name = string.Format("OBJ<Assets/ResourcesAssets/World/prefabs/sandtable/road/Cross_{0}.prefab>", key);
                    road.transform.parent = lod;
                    road.transform.eulerAngles = cross.transform.eulerAngles;
                    road.transform.localPosition = cross.transform.position;
                }
            }
        }

        #endregion

        void Update()
        {

            if (bload_osm_node)
            {
                GetOsmNodeData();
                this.Repaint();
            }
            if (bload_osm_way)
            {
                GetOsmWaysData();
                this.Repaint();
            }
            if (bload_osm_road)
            {
                GetRoads();
                this.Repaint();
            }
            if (bload_cfg_road)
            {
                GetRoadCfgData();
                this.Repaint();
            }
            if (Selection.gameObjects.Length == 1)
            {
                GameObject selectObj = Selection.gameObjects[0];
                bool broad = selectObj.name.Contains("road");
                if (broad)
                {
                    // 启动路点更新检查
                    if (script_select_road == null || selectObj != obj_select_last)
                    {
                        script_select_road = selectObj.GetComponentInParent<SandBoxRoadInfo>();
                        v3_select_last_pos = selectObj.gameObject.transform.localPosition;
                        obj_select_last = selectObj;
                    }
                }
                else
                {
                    script_select_road = null;
                }
            }
            else
            {
                if (script_select_road)
                {
                    script_select_road.UpdateRoadMesh();
                }
                script_select_road = null;
            }

            if (script_select_road != null)
            {
                // 检查点改变量
                GameObject selectObj = Selection.gameObjects[0];
                Vector3 cur = selectObj.gameObject.transform.localPosition;
                Vector3 dis_pos = cur - v3_select_last_pos;
                if (dis_pos.magnitude > 0.1f)
                {
                    string[] res = selectObj.name.Split('_');
                    int.TryParse(res[res.Length - 1], out int idx);
                    script_select_road.UpdateRoadPoint(idx, cur);
                    v3_select_last_pos = cur;
                }
            }

            if (b_editor_roadgroup && roadgroup != null)
            {
                f_delay_time -= Time.deltaTime;
                CheckGroupMove();
                CheckGroupRotate();
            }

        }

        void OnDestroy()
        {
            ClearObjs();
            EditorUtility.ClearProgressBar();
        }
    }
    public class MenuItem_SandBoxRoadEditor
    {
        [MenuItem("GTATools/GamePlay/SandBox/MapTools/Map/MapRoad")]
        static void MapEditorWindow()
        {
            EditorWindow.GetWindow<SandBoxRoadEditor>(false, "沙盒道路编辑器1.0");
        }
    }
}